/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Algorithm;

import com.google.common.collect.HashMultimap;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.imageio.ImageIO;

/**
 *
 * @author PaLam
 */
public class Main {

    private BufferedImage resizeImage;
    private BufferedImage originalImage;
    private byte[][][] imageByte;
    private int maxRec;
    private int minRec;
    private int ratio;
    private double[] red;
    private ArrayList<HashMultimap<String, Point>> result;
    private HashMultimap<String, Point> hm;
    private HashSet<String> found;

    private Main() {
        this.resizeImage = null;
        this.originalImage = null;
        this.imageByte = null;
        this.result = null;
        this.red = new double[]{0, 0, 255};
        this.ratio = 1; //ratio is original divide by resize
        this.minRec = 3;
    }

    public Main(String target) {
        this();
        try {
            originalImage = ImageIO.read(new File(target));
            resizeImage = (BufferedImage) originalImage.getScaledInstance(originalImage.getWidth() / ratio, originalImage.getHeight() / ratio, Image.SCALE_SMOOTH);
        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
    }

    private void BufferedImageToByte() {
        int d;
        imageByte = new byte[resizeImage.getHeight()][resizeImage.getWidth()][3];
        for (int i = 0; i < resizeImage.getHeight(); i++) {
            for (int j = 0; j < resizeImage.getWidth(); j++) {
                d = resizeImage.getRGB(i, j);
                imageByte[i][j][2] = (byte) (d & 255);
                imageByte[i][j][1] = (byte) (d >> 8 & 255);
                imageByte[i][j][0] = (byte) (d >> 16 & 255);
            }
        }
    }

    private void Hash(int i, int j, int rec) {
        List<Byte> hex = new ArrayList<>();
        String tempHash;
        try {
            for (int l = 0; l < rec; l++) {
                for (int k = 0; k < rec; k++) {
                    hex.add(imageByte[i + l][j + k][0]);
                    hex.add(imageByte[i + l][j + k][1]);
                    hex.add(imageByte[i + l][j + k][2]);
                }
            }
            tempHash = SubImageDigest.Digest(hex.toArray(new Byte[hex.size()]));
            if (hm.containsKey(tempHash)) {
                found.add(tempHash);
            }
            hm.put(tempHash, new Point(i, j));
        } catch (ArrayIndexOutOfBoundsException e) {
        }
    }

    /**
     * Start to processing all of sub-image to digest. And find duplicate
     * digest.
     */
    public void PrepareDB() {
        int row, col;
        HashMultimap<String, Point> tempResult = HashMultimap.create();
        hm = HashMultimap.create();
        found = new HashSet<>();
        result = new ArrayList<>();
        BufferedImageToByte();
        row = resizeImage.getHeight();
        col = resizeImage.getWidth();
        for (int i = 0; i < row - minRec; i++) {
            for (int j = 0; j < col - minRec; j++) {
                System.out.println("Row: " + i + " Col: " + j);
                Hash(i, j, minRec);
            }
        }
        for (String string : found) {
            tempResult.putAll(string, hm.get(string));
        }
        result.add(tempResult);

        for (int i = 0;; i++) {
            System.out.println("size: " + Integer.toString(i + minRec));
            tempResult = HashMultimap.create();
            for (String stringResult : result.get(i).keys()) {
                found.clear();
                hm.clear();
                for (Point point : result.get(i).get(stringResult)) {
                    Hash(point.x, point.y, minRec + i + 1);
                }
                if (found.size() == result.get(i).get(stringResult).size()) {
                    result.get(i).removeAll(stringResult);
                    System.out.println("Result duplicate");
                }
                for (String string : found) {
                    tempResult.putAll(string, hm.get(string));
                }
            }
            if (tempResult.size() == 0) {
                break;
            }
            result.add(tempResult);
        }
    }

}
